package com.hxzy.common.util;

import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import com.hxzy.common.constans.RedisConstans;
import com.hxzy.common.enums.AckCode;
import com.hxzy.common.exception.ServiceException;
import com.hxzy.controller.vue.login.resp.AdminLoginResp;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author wy
 * @Description 一个用户只允许登录一次，下次登录的时候，前一个用户就要被踢掉
 * @Date 2023/8/29 14:03
 * @Version 1.0
 */
@Component
@Log4j2
public class UniqueTokenService implements JwtTokenService<AdminLoginResp> {

    @Autowired
    private RedisTemplate redisTemplate;


    @Override
    public String createJwtToken(AdminLoginResp resp) {
        resp.setUuid(UUID.randomUUID().toString());

        this.refreshToken(resp);

        //把值加密成jwt
        Map<String, Object> claims = new HashMap<>();
        claims.put(UUID_KEY, resp.getUuid());
        claims.put(USER_ID, resp.getId());
        claims.put(USER_TYPE, resp.getPermissions().get(0));

        //生成jwt
        String jwtToken = JWTUtil.createToken(claims,  JWT_SECURITY.getBytes());

        return jwtToken;
    }

    @Override
    public void verifyToken(AdminLoginResp resp) {
        //剩余时间20分钟
        long twenty_minutes=1000L*60*20;
        long expireTime = resp.getExpired().getTime();
        long currentTime = System.currentTimeMillis();
        //redis过期时间<=20分钟，快过期了
        if (expireTime - currentTime <= twenty_minutes) {
            refreshToken(resp);
        }
    }

    @Override
    public void refreshToken(AdminLoginResp resp) {
        resp.setExpired(new Date(System.currentTimeMillis()+ (RedisConstans.ADMIN_TOKEN_EXPIRED_MINTUES * 60L*1000)));

        //只能使用id
        String redisKey=this.getReidsKey(resp.getPermissions().get(0),resp.getId()+"");

        this.redisTemplate.opsForValue().set(redisKey,resp,RedisConstans.ADMIN_TOKEN_EXPIRED_MINTUES, TimeUnit.MINUTES);

    }

    /**
     * 获取用户身份信息
     * @param jwtToken
     * @return
     */
    @Override
    public AdminLoginResp getLoginResp(String jwtToken) {
        //jwt令牌
        boolean isTrue = false;
        try {
            isTrue = JWTUtil.verify(jwtToken, JWT_SECURITY.getBytes(StandardCharsets.UTF_8));
        } catch (Exception e) {
            log.error(e);
        }

        if (isTrue) {
            //解析令牌中的值
            JWT jwt = JWTUtil.parseToken(jwtToken);
            //uuid
            String value = jwt.getPayload(UUID_KEY).toString();
            //用户类型
            String type = jwt.getPayload(USER_TYPE).toString();
            //用户id
            String userId = jwt.getPayload(USER_ID).toString();

            String redisKey = this.getReidsKey(type, userId);

            Object redisValue = this.redisTemplate.opsForValue().get(redisKey);

            if (Objects.nonNull(redisValue)) {
                //redis中的uuid是不是与当前的jwt中的uuid一致
                AdminLoginResp adminLoginResp = (AdminLoginResp) redisValue;
                //用户正常
                if (adminLoginResp.getUuid().equals(value)) {
                    return adminLoginResp;
                } else {
                    throw new ServiceException(AckCode.ACCOUNT_LOGIN_OTHER_DEVICES);
                }
            }
            return null;
        }

        return null;
    }

    @Override
    public void delLoginUser(AdminLoginResp resp) {
        String redisKey=this.getReidsKey(resp.getPermissions().get(0),resp.getId()+"");
        this.redisTemplate.delete(redisKey);
    }

    @Override
    public String getReidsKey(String type, String value) {
        String redisKey="";
        if(type.equals(ADMIN)){
            redisKey=RedisConstans.getRedisKey(RedisConstans.ADMIN_TOKEN_KEY,value);
        }else{
            redisKey=RedisConstans.getRedisKey(RedisConstans.MERCHANDISER_TOKEN_KEY,value);
        }
        return redisKey;
    }
}
